package cast

import (
	"fmt"
	"strings"

	"gitee.com/u-language/u-language/ucom/ast"
	"gitee.com/u-language/u-language/ucom/data"
	"gitee.com/u-language/u-language/ucom/enum"
	"gitee.com/u-language/u-language/ucom/internal/errutil"
	"gitee.com/u-language/u-language/ucom/internal/utils"
	"gitee.com/u-language/u-language/ucom/ir2"
)

type Ir2ToC struct {
	headerFile  data.Slice[ast.CHeaderFile]
	Nodes       []ast.Node
	packageName string
	isInitFunc  bool
	varInit     []ast.Node
}

func NewIr2ToC(packageName string, isInitFunc bool) *Ir2ToC {
	return &Ir2ToC{packageName: packageName, isInitFunc: isInitFunc}
}

func (c *Ir2ToC) C() string {
	defer Deferfunc()
	var buf strings.Builder
	buf.Grow(len(c.Nodes) * 50)
	buf.WriteString(includeStr)
	// if c.InAutoFree {
	// 	buf.WriteString("#include \"mempool.h\"\n")
	// }
	generateHeaderFile(c.headerFile.Data, nil, &buf)
	tion := generateInit2(c.packageName, c.isInitFunc, c.varInit, &buf, nil, false)
	generateCFileNoLF(c.Nodes, &buf)
	buf.WriteString("\n")
	buf.WriteString(tion)
	return buf.String()
}

// generateInit2 生成隐式调用init函数 返回init函数定义
//   - PackageName 是包名
//   - isInitFunc是否有自定义init函数
//   - node 是变量初始化节点
//   - fbuf 写入声明
//   - importLocal 是自己导入的包
//   - isImported 是否被导入
func generateInit2(PackageName string, isInitFunc bool, node []ast.Node, fbuf *strings.Builder, importLocal []*Package, isImported bool) string {
	var buf strings.Builder
	vil := len(node)
	var decl string = utils.GeneratePackageSymbol(PackageName, "init")
	//生成隐式init函数声明
	fbuf.WriteString("// --- 隐式init函数声明 ---\n")
	fbuf.WriteString("void ")
	fbuf.WriteString(decl)
	fbuf.WriteString("();\n")
	//生成隐式init函数定义
	f := ast.FuncNode{}
	f.FuncInfo = &ast.FuncInfo{}
	f.Name = decl
	f.C(&buf)
	fbuf.WriteString("\n")
	if !isImported { //如果不是被导入的包
		generateImportInitCallAll(importLocal, &buf)
	}
	buf.WriteString("\n")
	for i := 0; i < vil; i++ {
		node[i].C(&buf)
	}
	if isInitFunc { //如果有自定义的init函数
		buf.WriteString("// --- 调用自定义init函数 ---\n")
		decl = utils.GeneratePackageSymbol(PackageName, "init__user")
		//调用自定义init函数
		ast.NewCallExpr(ast.NewObject(ast.SymbolObj, decl), false).C(&buf)
		buf.WriteString(";\n")
	}
	buf.WriteString("\n}\n")
	return buf.String()
}

func PaeserIr2(toc *Ir2ToC, f *ir2.File) {
	//处理全局声明
	for _, v := range f.GlobalDecl {
		toc.headerFile.Add(ast.CHeaderFile{N: v.(ast.CDecl), Line: retNodeLine(v)})
	}
	//处理变量初始化
	for _, v := range f.VarInit {
		toc.varInit = append(toc.varInit, OneIr2ToC(v))
	}
	//处理指令
	toc.Nodes = make([]ast.Node, len(f.Ir))
	for i, v := range f.Ir {
		toc.Nodes[i] = OneIr2ToC(v)
	}
}

func retNodeLine(n ast.Node) int {
	switch node := n.(type) {
	case *ast.VarNode:
		return node.LineNum
	case *ast.FuncNode:
		return node.LineNum
	case *ast.MethodNode:
		return node.LineNum
	case *ast.StructDecl:
		return node.LineNum
	default:
		panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未知的节点：%+v", n)))
	}
}

type OneIr2ToC ir2.IrNode

func (ir OneIr2ToC) C(buf *strings.Builder) {
	ir2ToC(ir2.IrNode(ir), buf)
}

func (ir OneIr2ToC) String() string {
	var buf strings.Builder
	ir2ToC(ir2.IrNode(ir), &buf)
	return buf.String()
}

func ir2ToC(ir ir2.IrNode, buf *strings.Builder) {
	switch ir.Op {
	case ir2.ADDOP, ir2.SUBOP, ir2.MULOP, ir2.DIVOP, ir2.LessOp, ir2.GreaterOp, ir2.EqualOp, ir2.NoEqualOp, ir2.RemainOp:
		if ir.ResultObj == enum.StrFalse { //如果指令不包含操作的值
			buf.WriteString(ir2opToStr[ir.Op])
			return
		}
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(ir2opToStr[ir.Op])
		buf.WriteString(ir.Arg2Obj)
		if ir.ResultTyp != enum.StrFalse { //如果不是不换行
			buf.WriteString(";\n")
		}
	case ir2.MOVOP:
		buf.WriteString(ir.ResultObj)
		buf.WriteString(" = ")
		if ir.Arg2Obj != enum.StrFalse { //如果不是不包含源操作数
			buf.WriteString(ir.Arg1Obj)
			buf.WriteString(";\n")
		}
	case ir2.RbraceOP:
		buf.WriteString("}\n")
	case ir2.FuncOP:
		n := **ir.Func()
		if f, ok := n.(*ast.FuncNode); ok {
			cf := f
			cf.C(buf)
		} else {
			f := n.(*ast.MethodNode)
			f.C(buf)
		}
		buf.WriteString("\n")
	case ir2.VarOP:
		n := *ir.Var()
		n.Value = nil
		n.C(buf)
		buf.WriteString("\n")
	case ir2.TmpVarOP:
		buf.WriteString(typeToC(ir.Arg2Obj)) //这是类型
		buf.WriteString(" ")
		buf.WriteString(ir.Arg1Obj) //这是临时变量名
		buf.WriteString(";\n")
	case ir2.TypeConvertOp:
		buf.WriteString("(")
		buf.WriteString(typeToC(ir.Arg1Obj))
		buf.WriteString(")")
		buf.WriteString(ir.Arg2Obj)
	case ir2.CallOP:
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString("(")
		noparame := ir.ResultObj == enum.StrFalse
		if noparame { //如果没有参数
			buf.WriteString(")")
		}
		if noparame && ir.ResultTyp != enum.StrFalse { //如果没有参数,同时不是不换行
			buf.WriteString(";\n")
		}
	case ir2.EndCallOp:
		buf.WriteString(")")
		if ir.ResultTyp != enum.StrFalse { //如果不是不换行
			buf.WriteString(";\n")
		}
	case ir2.PaPaOp:
		buf.WriteString(ir.Arg2Obj)
		if ir.ResultObj != enum.StrFalse { //如果不是最后一个传参
			buf.WriteString(",")
		}
	case ir2.RetOp:
		buf.WriteString("return ")
		if ir.Arg2Obj == enum.StrFalse { //如果返回值不在后面，也就是直接有返回值
			buf.WriteString(ir.Arg1Obj)
			buf.WriteString(";\n")
		}
	case ir2.ForOp:
		buf.WriteString("for (")
	case ir2.SemicolonOp:
		buf.WriteString(" ; ")
	case ir2.CommaOp:
		buf.WriteString(" , ")
	case ir2.ObjOP:
		buf.WriteString(ir.ResultObj)
	case ir2.LbraceOp:
		buf.WriteString(" { ")
	case ir2.LineFeedOp:
		buf.WriteString("\n")
	case ir2.LocalVarOp:
		buf.WriteString(typeToC((**ir.Type()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(" =")
	case ir2.RPARENOp:
		buf.WriteString(" ) ")
	case ir2.ElseOp:
		buf.WriteString("else {\n")
	case ir2.ElseIfOp:
		buf.WriteString("else if (")
		boolexprToC(ir, buf)
	case ir2.IfOp:
		buf.WriteString("if (")
		boolexprToC(ir, buf)
	case ir2.Field:
		buf.WriteString(typeToC((**ir.Arg1ObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(";\n")
	case ir2.Field3:
		buf.WriteString(typeToC((**ir.Arg1ObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(";\n")
		buf.WriteString(typeToC((**ir.Arg2ObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg2Obj)
		buf.WriteString(";\n")
		buf.WriteString(typeToC((**ir.ResultObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.ResultObj)
		buf.WriteString(";\n")
	case ir2.StructDeclStart:
		buf.WriteString("typedef struct {\n")
	case ir2.Struct1Field:
		buf.WriteString("typedef struct {\n")
		buf.WriteString(typeToC((**ir.Arg1ObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(";")
	case ir2.Struct2Field:
		buf.WriteString("typedef struct {\n")
		buf.WriteString(typeToC((**ir.Arg1ObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(";\n")
		buf.WriteString(typeToC((**ir.Arg2ObjTyp()).Typ()))
		buf.WriteString(" ")
		buf.WriteString(ir.Arg2Obj)
		buf.WriteString(";")
	case ir2.StructDeclEnd:
		buf.WriteString("\n}")
		buf.WriteString(ir.ResultObj)
		buf.WriteString(";\n")
	case ir2.SelectRight:
		buf.WriteString(".")
		buf.WriteString(ir.Arg1Obj)
	case ir2.LeftSelectRight:
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(".")
		buf.WriteString(ir.Arg2Obj)
	case ir2.AssignOp:
		buf.WriteString("=")
	case ir2.Malloc:
		buf.WriteString("malloc(sizeof(")
		n := ir.Arg1ObjExpr()
		(**n).(ast.CType).CType(buf)
		buf.WriteString("))")
		if ir.ResultTyp != enum.StrFalse { //如果不是不换行
			buf.WriteString("\n")
		}
	default:
		panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未知的ir：%+v", ir)))
	}
}

func boolexprToC(ir ir2.IrNode, buf *strings.Builder) {
	if ir.Arg2Obj == enum.StrFalse { //如果布尔表达式在ir里
		buf.WriteString(ir.Arg1Obj)
		buf.WriteString(")}")
		return
	}
}

var ir2opToStr = map[ir2.OPEnum]string{
	ir2.ADDOP:     " + ",
	ir2.SUBOP:     " - ",
	ir2.MULOP:     " * ",
	ir2.DIVOP:     " / ",
	ir2.LessOp:    " < ",
	ir2.GreaterOp: " > ",
	ir2.EqualOp:   " == ",
	ir2.NoEqualOp: " != ",
	ir2.RemainOp:  " % ",
}
